dash_charts.app_px⚓︎
Generic Plotly Express Data Analysis App(s).
Examples: https://www.plotly.express/
Docs: https://www.plotly.express/plotly_express/
(Currently) Unsupported plotly express types⚓︎
px.parallel_coordinates(px.data.iris(), color="species_id",
dimensions=['sepal_width', 'sepal_length', 'petal_width', 'petal_length'])
px.treemap(px.data.tips(), path=['day', 'time', 'sex'], values='total_bill')
px.sunburst(px.data.tips(), path=['day', 'time', 'sex'], values='total_bill)
Other charts that could be useful (but won’t work with simple dropdowns)
- scatter_matrix([data_frame, dimensions, …])
- In a scatter plot matrix (or SPLOM), each row of data_frame is
- https://plotly.com/python/splom/
- parallel_coordinates([data_frame, …])
- In a parallel coordinates plot, each row of data_frame is represented
- https://plotly.com/python-api-reference/generated/plotly.express.parallel_coordinates.html
- parallel_categories([data_frame, …])
- In a parallel categories (or parallel sets) plot, each row of
- https://plotly.com/python-api-reference/generated/plotly.express.parallel_categories.html
- density_heatmap([data_frame, x, y, z, …])
- In a density heatmap, rows of data_frame are grouped together into
- https://plotly.com/python-api-reference/generated/plotly.express.density_heatmap.html
- imshow(img[, zmin, zmax, origin, …])
- Display an image, i.e.
- https://plotly.com/python/imshow/
View Source
"""Generic Plotly Express Data Analysis App(s).
Examples: https://www.plotly.express/
Docs: https://www.plotly.express/plotly_express/
# (Currently) Unsupported plotly express types
```py
px.parallel_coordinates(px.data.iris(), color="species_id",
dimensions=['sepal_width', 'sepal_length', 'petal_width', 'petal_length'])
px.treemap(px.data.tips(), path=['day', 'time', 'sex'], values='total_bill')
px.sunburst(px.data.tips(), path=['day', 'time', 'sex'], values='total_bill)
Other charts that could be useful (but won’t work with simple dropdowns)
- scatter_matrix([data_frame, dimensions, …])
- In a scatter plot matrix (or SPLOM), each row of data_frame is
- https://plotly.com/python/splom/
- parallel_coordinates([data_frame, …])
- In a parallel coordinates plot, each row of data_frame is represented
- https://plotly.com/python-api-reference/generated/plotly.express.parallel_coordinates.html
- parallel_categories([data_frame, …])
- In a parallel categories (or parallel sets) plot, each row of
- https://plotly.com/python-api-reference/generated/plotly.express.parallel_categories.html
- density_heatmap([data_frame, x, y, z, …])
- In a density heatmap, rows of data_frame are grouped together into
- https://plotly.com/python-api-reference/generated/plotly.express.density_heatmap.html
- imshow(img[, zmin, zmax, origin, …])
- Display an image, i.e.
- https://plotly.com/python/imshow/
”“”
from collections import OrderedDict
import dash import dash_bootstrap_components as dbc import pandas as pd import plotly.express as px from dash import html from implements import implements
from .components import dropdown_group, opts_dd from .utils_app import AppBase, AppInterface from .utils_app_with_navigation import FullScreenAppWithTabs from .utils_callbacks import map_args, map_outputs from .utils_fig import min_graph
======================================================================================================================⚓︎
Create classes to manage tabs state. Easy to scale up or down⚓︎
>> Demo uses sample data. User could replace with data loaded from a static CSV file, TinyDB, SQLite, etc.⚓︎
@implements(AppInterface) # noqa: H601 class TabBase(AppBase): “”“Base tab class with helper methods.”“”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | |
@implements(AppInterface) # noqa: H601 class TabTip(TabBase): “”“TabTip properties.”“”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
@implements(AppInterface) # noqa: H601 class TabIris(TabBase): “”“TabIris properties.”“”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
@implements(AppInterface) # noqa: H601 class TabGapminder(TabBase): “”“TabGapminder properties.”“”
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
@implements(AppInterface) # noqa: H601 class TabTernary(TabBase): “”“TabTernary properties.”“”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
@implements(AppInterface) # noqa: H601 class TabWind(TabBase): “”“TabWind properties.”“”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
@implements(AppInterface) # noqa: H601 class TabColor(TabBase): “”“TabColor properties.”“”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
======================================================================================================================⚓︎
Create class for application to control manage variable scopes⚓︎
class InteractivePXApp(FullScreenAppWithTabs): # noqa: H601 “”“Plotly Express Demo application.”“”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
```
Classes⚓︎
InteractivePXApp⚓︎
class InteractivePXApp(
app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class InteractivePXApp(FullScreenAppWithTabs): # noqa: H601
"""Plotly Express Demo application."""
name = 'TabAppDemo'
tabs_location = 'right'
"""Tab orientation setting. One of `(left, top, bottom, right)`."""
tabs_margin = '175px'
"""Adjust this setting based on the width or height of the tabs to prevent the content from overlapping the tabs."""
tabs_compact = False
"""Boolean setting to toggle between a padded tab layout if False and a minimal compact version if True."""
def define_nav_elements(self):
"""Return list of initialized tabs.
Returns:
list: each item is an initialized tab (ex `[AppBase(self.app)]` in the order each tab is rendered
"""
return [
TabTip(app=self.app),
TabIris(app=self.app),
TabGapminder(app=self.app),
TabTernary(app=self.app),
TabWind(app=self.app),
TabColor(app=self.app),
]
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
return html.Div([
html.H1('Dash/Plotly Express Data Exploration Demo', style={'padding': '15px 0 0 15px'}),
super().return_layout(),
])
Ancestors (in MRO)⚓︎
- dash_charts.utils_app_with_navigation.FullScreenAppWithTabs
- dash_charts.utils_app_with_navigation.AppWithTabs
- dash_charts.utils_app_with_navigation.AppWithNavigation
- dash_charts.utils_app.AppBase
Class variables⚓︎
app
app_ids
external_stylesheets
id_tabs_content
id_tabs_select
init_app_kwargs
modules
name
nav_layouts
nav_lookup
nsi
tabs_compact
Boolean setting to toggle between a padded tab layout if False and a minimal compact version if True.
tabs_location
Tab orientation setting. One of (left, top, bottom, right).
tabs_margin
Adjust this setting based on the width or height of the tabs to prevent the content from overlapping the tabs.
validation_layout
Methods⚓︎
callback⚓︎
def callback(
self,
outputs,
inputs,
states,
pic: bool = False,
**kwargs: dict
)
Return app callback decorator based on provided components.
Parameters:
| Name | Description |
|---|---|
| outputs | list of tuples with app_id and property name |
| inputs | list of tuples with app_id and property name |
| states | list of tuples with app_id and property name |
| pic | If True, prevent call on page load (prevent_initial_call). Default is False |
| **kwargs | any additional keyword arguments for self.app.callback |
Returns:
| Type | Description |
|---|---|
| dict | result of self.app.callback() |
View Source
def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
"""Return app callback decorator based on provided components.
Args:
outputs: list of tuples with app_id and property name
inputs: list of tuples with app_id and property name
states: list of tuples with app_id and property name
pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
**kwargs: any additional keyword arguments for `self.app.callback`
Returns:
dict: result of `self.app.callback()`
"""
return self.app.callback(
*format_app_callback(self._il, outputs, inputs, states),
prevent_initial_call=pic,
**kwargs,
)
create⚓︎
def create(
self,
**kwargs
)
Create each navigation componet, storing the layout. Then parent class to create application.
Parameters:
| Name | Description |
|---|---|
| kwargs | keyword arguments passed to self.create |
View Source
def create(self, **kwargs):
"""Create each navigation componet, storing the layout. Then parent class to create application.
Args:
kwargs: keyword arguments passed to `self.create`
"""
# Initialize the lookup for each tab then configure each tab
self.nav_lookup = OrderedDict([(tab.name, tab) for tab in self.define_nav_elements()])
self.nav_layouts = {}
for nav_name, nav in self.nav_lookup.items():
nav.create(assign_layout=False)
self.nav_layouts[nav_name] = nav.return_layout()
# Store validation_layout that is later used for callback verification in base class
self.validation_layout = [*map(deepcopy, self.nav_layouts.values())]
# Initialize parent application that handles navigation
super().create(**kwargs)
create_callbacks⚓︎
def create_callbacks(
self
) -> None
Register the navigation callback.
View Source
def create_callbacks(self) -> None:
"""Register the navigation callback."""
outputs = [(self.id_tabs_content, 'children')]
inputs = [(self.id_tabs_select, 'value')]
@self.callback(outputs, inputs, [])
def render_tab(tab_name):
return [self.nav_layouts[tab_name]]
create_elements⚓︎
def create_elements(
self
) -> None
Override method as not needed at navigation-level.
View Source
def create_elements(self) -> None:
"""Override method as not needed at navigation-level."""
... # pragma: no cover
define_nav_elements⚓︎
def define_nav_elements(
self
)
Return list of initialized tabs.
Returns:
| Type | Description |
|---|---|
| list | each item is an initialized tab (ex [AppBase(self.app)] in the order each tab is rendered |
View Source
def define_nav_elements(self):
"""Return list of initialized tabs.
Returns:
list: each item is an initialized tab (ex `[AppBase(self.app)]` in the order each tab is rendered
"""
return [
TabTip(app=self.app),
TabIris(app=self.app),
TabGapminder(app=self.app),
TabTernary(app=self.app),
TabWind(app=self.app),
TabColor(app=self.app),
]
generate_data⚓︎
def generate_data(
self
) -> None
Recommended method for generating data stored in memory. Called in initialization.
View Source
def generate_data(self) -> None:
"""Recommended method for generating data stored in memory. Called in initialization."""
...
generate_tab_kwargs⚓︎
def generate_tab_kwargs(
self
)
Create the tab keyword arguments. Intended to be modified through inheritance.
Returns:
| Type | Description |
|---|---|
| tuple | keyword arguments and styling for the dcc.Tab elements |
- tab_kwargs: with at minimum keys (style, selected_style) for dcc.Tab |
|
| - tabs_kwargs: to be passed to dcc.Tabs | |
| - tabs_style: style for the dcc.Tabs HTML element |
View Source
def generate_tab_kwargs(self):
"""Create the tab keyword arguments. Intended to be modified through inheritance.
Returns:
tuple: keyword arguments and styling for the dcc.Tab elements
- tab_kwargs: with at minimum keys `(style, selected_style)` for dcc.Tab
- tabs_kwargs: to be passed to dcc.Tabs
- tabs_style: style for the dcc.Tabs HTML element
"""
# Unselected tab style
if self.tabs_compact:
tab_style = {'padding': '2px 4px 2px 4px'}
tabs_padding = '6px 0 0 2px'
else:
tab_style = {'padding': '10px 20px 10px 20px'}
tabs_padding = '15px 0 0 5px'
# Extend tab style for selected case
selected_style = deepcopy(tab_style)
opposite_lookup = {'top': 'bottom', 'bottom': 'top', 'left': 'right', 'right': 'left'}
tabs_style = { # noqa: ECE001
'backgroundColor': '#F9F9F9',
'padding': tabs_padding,
'position': 'fixed',
'zIndex': '999',
f'border{opposite_lookup[self.tabs_location].title()}': '1px solid #d6d6d6',
self.tabs_location: '0',
}
if self.tabs_location in ['left', 'right']:
# Configure for vertical case
selected_style['border-left'] = '3px solid #119DFF'
tabs_kwargs = {
'vertical': True,
'style': {'width': '100%'},
'parent_style': {'width': '100%'},
}
tabs_style['top'] = '0'
tabs_style['bottom'] = '0'
tabs_style['width'] = 'auto'
else:
# Configure for horizontal case
selected_style['border-top'] = '3px solid #119DFF'
tabs_kwargs = {}
tabs_style['height'] = 'auto'
tabs_style['right'] = '0'
tabs_style['left'] = '0'
tab_kwargs = {'style': tab_style, 'selected_style': selected_style}
return (tab_kwargs, tabs_kwargs, tabs_style)
get_server⚓︎
def get_server(
self
)
Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
| Type | Description |
|---|---|
| dict | the Flask server component of the Dash app |
View Source
def get_server(self):
"""Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
dict: the Flask `server` component of the Dash app
"""
return self.app.server
initialization⚓︎
def initialization(
self
) -> None
Initialize ids with self.register_uniq_ids([...]) and other one-time actions.
View Source
def initialization(self) -> None:
"""Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
super().initialization()
self.register_uniq_ids(self.app_ids)
override_module_defaults⚓︎
def override_module_defaults(
self
) -> None
Override default values from modules.
View Source
def override_module_defaults(self) -> None:
"""Override default values from modules."""
...
register_uniq_ids⚓︎
def register_uniq_ids(
self,
app_ids: List[str]
) -> None
Register the app_ids to the corresponding global_id in the self._il lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers self._il
which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Parameters:
| Name | Description |
|---|---|
| app_ids | list of strings that are unique within this App |
View Source
def register_uniq_ids(self, app_ids: List[str]) -> None:
"""Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Args:
app_ids: list of strings that are unique within this App
"""
self._il = deepcopy(self._il)
for app_id in app_ids:
self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')
return_layout⚓︎
def return_layout(
self
) -> dict
Return Dash application layout.
Returns:
| Type | Description |
|---|---|
| dict | Dash HTML object |
View Source
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
return html.Div([
html.H1('Dash/Plotly Express Data Exploration Demo', style={'padding': '15px 0 0 15px'}),
super().return_layout(),
])
run⚓︎
def run(
self,
**dash_kwargs: dict
) -> None
Launch the Dash server instance.
Parameters:
| Name | Description |
|---|---|
| **dash_kwargs | keyword arguments for Dash.run_server() |
View Source
def run(self, **dash_kwargs: dict) -> None:
"""Launch the Dash server instance.
Args:
**dash_kwargs: keyword arguments for `Dash.run_server()`
"""
self.app.run_server(**dash_kwargs) # pragma: no cover
tab_menu⚓︎
def tab_menu(
self
)
Return the HTML elements for the tab menu.
Returns:
| Type | Description |
|---|---|
| dict | Dash HTML object |
View Source
def tab_menu(self):
"""Return the HTML elements for the tab menu.
Returns:
dict: Dash HTML object
"""
tab_kwargs, tabs_kwargs, tabs_style = self.generate_tab_kwargs()
tabs = [dcc.Tab(label=name, value=name, **tab_kwargs) for name, tab in self.nav_lookup.items()]
return html.Div(
children=[
dcc.Tabs(
id=self._il[self.id_tabs_select], value=list(self.nav_lookup.keys())[0],
children=tabs, **tabs_kwargs,
),
], style=tabs_style,
)
verify_app_initialization⚓︎
def verify_app_initialization(
self
)
Check that the app was properly initialized.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if child class has not called self.register_uniq_ids |
View Source
def verify_app_initialization(self):
"""Check that the app was properly initialized.
Raises:
RuntimeError: if child class has not called `self.register_uniq_ids`
"""
super().verify_app_initialization()
allowed_locations = ('left', 'top', 'bottom', 'right')
if self.tabs_location not in allowed_locations: # pragma: no cover
raise RuntimeError(f'`self.tabs_location = {self.tabs_location}` is not in {allowed_locations}')
TabBase⚓︎
class TabBase(
app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabBase(AppBase):
"""Base tab class with helper methods."""
external_stylesheets = [dbc.themes.FLATLY]
# ID Elements for UI
id_chart: str = 'chart'
id_func: str = 'func'
id_template: str = 'template' # PLANNED: template should be able to be None
takes_args: bool = True
"""If True, will pass arguments from UI to function."""
templates: list = [
'ggplot2', 'seaborn', 'simple_white', 'plotly',
'plotly_white', 'plotly_dark', 'presentation', 'xgridoff',
'ygridoff', 'gridon', 'none',
]
"""List of templates from: `import plotly.io as pio; pio.templates`"""
# Must override in child class
name: str = None
"""Unique tab component name. Must be overridden in child class."""
data: pd.DataFrame = None
"""Dataframe. Must be overridden in child class."""
func_map: OrderedDict = None
"""Map of functions to keywords. Must be overridden in child class."""
# PLANNED: below items should be able to be None
dims: tuple = ()
"""Keyword from function for dropdowns with column names as options. Must be overridden in child class."""
dims_dict: OrderedDict = OrderedDict([])
"""OrderedDict of keyword from function to allowed values. Must be overridden in child class."""
default_dim_name = {}
"""Lookup for dim:column name to use as default in dropdown."""
def initialization(self) -> None:
"""Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
super().initialization()
# Register the the unique element IDs
self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
self.register_uniq_ids([self.id_chart] + self.input_ids)
# Configure the options for the various dropdowns
self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
self.t_opts = tuple(opts_dd(template, template) for template in self.templates)
def create_elements(self) -> None:
"""Initialize the charts, tables, and other Dash elements."""
...
def verify_types_for_layout(self):
"""Verify data types of data members necessary for the layout of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.name, str):
errors.append(f'Expected self.name="{self.name}" to be str')
if not isinstance(self.dims, tuple):
errors.append(f'Expected self.dims="{self.dims}" to be tuple')
if not isinstance(self.dims_dict, OrderedDict):
errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
def verify_types_for_callbacks(self):
"""Verify data types of data members necessary for the callbacks of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.takes_args, bool):
errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
if not (isinstance(self.data, pd.DataFrame) or self.data is None):
errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
if not isinstance(self.func_map, OrderedDict):
errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
self.verify_types_for_layout()
return html.Div(
[ # noqa: ECE001
html.Div(
[
dropdown_group(
'Plot Type:', self._il[self.id_func],
self.func_opts, value=self.func_opts[0]['label'],
),
dropdown_group(
'Template:', self._il[self.id_template],
self.t_opts, value=self.t_opts[0]['label'],
),
] + [
dropdown_group(
f'{dim}:', self._il[dim], self.col_opts,
value=self.default_dim_name.get(dim, None),
)
for dim in self.dims
] + [
dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
for dim, items in self.dims_dict.items()
], style={'width': '25%', 'float': 'left'},
),
min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
], style={'padding': '15px'},
)
def create_callbacks(self) -> None:
"""Register callbacks necessary for this tab."""
self.verify_types_for_callbacks()
self.register_update_chart()
def register_update_chart(self): # noqa: CCR001
"""Register the update_chart callback."""
outputs = [(self.id_chart, 'figure')]
inputs = [(_id, 'value') for _id in self.input_ids]
states = ()
@self.callback(outputs, inputs, states)
def update_chart(*raw_args):
a_in, _a_states = map_args(raw_args, inputs, states)
name_func = a_in[self.id_func]['value']
properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
new_chart = {}
# If event is not a tab change, return the updated chart
if 'tabs-select.value' not in properties: # FIXME: replace tabs-select with actual keyname (?)
if self.takes_args:
# Parse the arguments to generate a new plot
kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
else:
new_chart = self.func_map[name_func]()
# Example Mapping Output. Alternatively, just: `return [new_chart]`
return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])
Ancestors (in MRO)⚓︎
- dash_charts.utils_app.AppBase
Descendants⚓︎
- dash_charts.app_px.TabTip
- dash_charts.app_px.TabIris
- dash_charts.app_px.TabGapminder
- dash_charts.app_px.TabTernary
- dash_charts.app_px.TabWind
- dash_charts.app_px.TabColor
Class variables⚓︎
data
default_dim_name
Lookup for dim:column name to use as default in dropdown.
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout
Methods⚓︎
callback⚓︎
def callback(
self,
outputs,
inputs,
states,
pic: bool = False,
**kwargs: dict
)
Return app callback decorator based on provided components.
Parameters:
| Name | Description |
|---|---|
| outputs | list of tuples with app_id and property name |
| inputs | list of tuples with app_id and property name |
| states | list of tuples with app_id and property name |
| pic | If True, prevent call on page load (prevent_initial_call). Default is False |
| **kwargs | any additional keyword arguments for self.app.callback |
Returns:
| Type | Description |
|---|---|
| dict | result of self.app.callback() |
View Source
def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
"""Return app callback decorator based on provided components.
Args:
outputs: list of tuples with app_id and property name
inputs: list of tuples with app_id and property name
states: list of tuples with app_id and property name
pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
**kwargs: any additional keyword arguments for `self.app.callback`
Returns:
dict: result of `self.app.callback()`
"""
return self.app.callback(
*format_app_callback(self._il, outputs, inputs, states),
prevent_initial_call=pic,
**kwargs,
)
create⚓︎
def create(
self,
assign_layout: bool = True
) -> None
Create the ids, app charts, layout, callbacks, and optional modules.
Parameters:
| Name | Description |
|---|---|
| assign_layout | if True, will assign self.app.layout. If False, must call self.return_layout separately.Default is True |
Raises:
| Type | Description |
|---|---|
| NotImplementedError | if child class has not set the self.name data member |
View Source
def create(self, assign_layout: bool = True) -> None: # noqa: CCR001
"""Create the ids, app charts, layout, callbacks, and optional modules.
Args:
assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
Default is True
Raises:
NotImplementedError: if child class has not set the `self.name` data member
"""
if self.name is None: # pragma: no cover
raise NotImplementedError('Child class must set `self.name` to a unique string for this app')
# Initialize app and each module
self.initialization()
for mod in self.modules:
self.register_uniq_ids(mod.all_ids)
self.override_module_defaults() # Call optional override method
# Create charts for app and each module
self.create_elements()
for mod in self.modules:
mod.create_elements(self._il)
# Create app layout. User must call the return_layout method from each module within own return_layout method
if assign_layout:
self.app.layout = self.return_layout()
if assign_layout and self.validation_layout:
self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
pprint('\n\nValidationLayout?')
pprint(self.app.validation_layout)
# Create callbacks for app and each module
self.create_callbacks()
for mod in self.modules:
mod.create_callbacks(self)
self.verify_app_initialization()
create_callbacks⚓︎
def create_callbacks(
self
) -> None
Register callbacks necessary for this tab.
View Source
def create_callbacks(self) -> None:
"""Register callbacks necessary for this tab."""
self.verify_types_for_callbacks()
self.register_update_chart()
create_elements⚓︎
def create_elements(
self
) -> None
Initialize the charts, tables, and other Dash elements.
View Source
def create_elements(self) -> None:
"""Initialize the charts, tables, and other Dash elements."""
...
generate_data⚓︎
def generate_data(
self
) -> None
Recommended method for generating data stored in memory. Called in initialization.
View Source
def generate_data(self) -> None:
"""Recommended method for generating data stored in memory. Called in initialization."""
...
get_server⚓︎
def get_server(
self
)
Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
| Type | Description |
|---|---|
| dict | the Flask server component of the Dash app |
View Source
def get_server(self):
"""Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
dict: the Flask `server` component of the Dash app
"""
return self.app.server
initialization⚓︎
def initialization(
self
) -> None
Initialize ids with self.register_uniq_ids([...]) and other one-time actions.
View Source
def initialization(self) -> None:
"""Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
super().initialization()
# Register the the unique element IDs
self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
self.register_uniq_ids([self.id_chart] + self.input_ids)
# Configure the options for the various dropdowns
self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
self.t_opts = tuple(opts_dd(template, template) for template in self.templates)
override_module_defaults⚓︎
def override_module_defaults(
self
) -> None
Override default values from modules.
View Source
def override_module_defaults(self) -> None:
"""Override default values from modules."""
...
register_uniq_ids⚓︎
def register_uniq_ids(
self,
app_ids: List[str]
) -> None
Register the app_ids to the corresponding global_id in the self._il lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers self._il
which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Parameters:
| Name | Description |
|---|---|
| app_ids | list of strings that are unique within this App |
View Source
def register_uniq_ids(self, app_ids: List[str]) -> None:
"""Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Args:
app_ids: list of strings that are unique within this App
"""
self._il = deepcopy(self._il)
for app_id in app_ids:
self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')
register_update_chart⚓︎
def register_update_chart(
self
)
Register the update_chart callback.
View Source
def register_update_chart(self): # noqa: CCR001
"""Register the update_chart callback."""
outputs = [(self.id_chart, 'figure')]
inputs = [(_id, 'value') for _id in self.input_ids]
states = ()
@self.callback(outputs, inputs, states)
def update_chart(*raw_args):
a_in, _a_states = map_args(raw_args, inputs, states)
name_func = a_in[self.id_func]['value']
properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
new_chart = {}
# If event is not a tab change, return the updated chart
if 'tabs-select.value' not in properties: # FIXME: replace tabs-select with actual keyname (?)
if self.takes_args:
# Parse the arguments to generate a new plot
kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
else:
new_chart = self.func_map[name_func]()
# Example Mapping Output. Alternatively, just: `return [new_chart]`
return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])
return_layout⚓︎
def return_layout(
self
) -> dict
Return Dash application layout.
Returns:
| Type | Description |
|---|---|
| dict | Dash HTML object |
View Source
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
self.verify_types_for_layout()
return html.Div(
[ # noqa: ECE001
html.Div(
[
dropdown_group(
'Plot Type:', self._il[self.id_func],
self.func_opts, value=self.func_opts[0]['label'],
),
dropdown_group(
'Template:', self._il[self.id_template],
self.t_opts, value=self.t_opts[0]['label'],
),
] + [
dropdown_group(
f'{dim}:', self._il[dim], self.col_opts,
value=self.default_dim_name.get(dim, None),
)
for dim in self.dims
] + [
dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
for dim, items in self.dims_dict.items()
], style={'width': '25%', 'float': 'left'},
),
min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
], style={'padding': '15px'},
)
run⚓︎
def run(
self,
**dash_kwargs: dict
) -> None
Launch the Dash server instance.
Parameters:
| Name | Description |
|---|---|
| **dash_kwargs | keyword arguments for Dash.run_server() |
View Source
def run(self, **dash_kwargs: dict) -> None:
"""Launch the Dash server instance.
Args:
**dash_kwargs: keyword arguments for `Dash.run_server()`
"""
self.app.run_server(**dash_kwargs) # pragma: no cover
verify_app_initialization⚓︎
def verify_app_initialization(
self
) -> None
Check that the app was properly initialized.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if child class has not called self.register_uniq_ids |
View Source
def verify_app_initialization(self) -> None:
"""Check that the app was properly initialized.
Raises:
RuntimeError: if child class has not called `self.register_uniq_ids`
"""
if not self._il.keys(): # pragma: no cover
raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')
verify_types_for_callbacks⚓︎
def verify_types_for_callbacks(
self
)
Verify data types of data members necessary for the callbacks of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_callbacks(self):
"""Verify data types of data members necessary for the callbacks of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.takes_args, bool):
errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
if not (isinstance(self.data, pd.DataFrame) or self.data is None):
errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
if not isinstance(self.func_map, OrderedDict):
errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
verify_types_for_layout⚓︎
def verify_types_for_layout(
self
)
Verify data types of data members necessary for the layout of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_layout(self):
"""Verify data types of data members necessary for the layout of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.name, str):
errors.append(f'Expected self.name="{self.name}" to be str')
if not isinstance(self.dims, tuple):
errors.append(f'Expected self.dims="{self.dims}" to be tuple')
if not isinstance(self.dims_dict, OrderedDict):
errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
TabColor⚓︎
class TabColor(
app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabColor(TabBase):
"""TabColor properties."""
name = 'Color Swatches'
takes_args = False
func_map = OrderedDict([
('colors.qualitative', px.colors.qualitative.swatches),
('colors.sequential', px.colors.sequential.swatches),
('colors.diverging', px.colors.diverging.swatches),
('colors.cyclical', px.colors.cyclical.swatches),
('colors.colorbrewer', px.colors.colorbrewer.swatches),
('colors.cmocean', px.colors.cmocean.swatches),
('colors.carto', px.colors.carto.swatches),
])
default_dim_name = {
'x': 'sepal_width',
'y': 'sepal_length',
}
Ancestors (in MRO)⚓︎
- dash_charts.app_px.TabBase
- dash_charts.utils_app.AppBase
Class variables⚓︎
data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout
Methods⚓︎
callback⚓︎
def callback(
self,
outputs,
inputs,
states,
pic: bool = False,
**kwargs: dict
)
Return app callback decorator based on provided components.
Parameters:
| Name | Description |
|---|---|
| outputs | list of tuples with app_id and property name |
| inputs | list of tuples with app_id and property name |
| states | list of tuples with app_id and property name |
| pic | If True, prevent call on page load (prevent_initial_call). Default is False |
| **kwargs | any additional keyword arguments for self.app.callback |
Returns:
| Type | Description |
|---|---|
| dict | result of self.app.callback() |
View Source
def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
"""Return app callback decorator based on provided components.
Args:
outputs: list of tuples with app_id and property name
inputs: list of tuples with app_id and property name
states: list of tuples with app_id and property name
pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
**kwargs: any additional keyword arguments for `self.app.callback`
Returns:
dict: result of `self.app.callback()`
"""
return self.app.callback(
*format_app_callback(self._il, outputs, inputs, states),
prevent_initial_call=pic,
**kwargs,
)
create⚓︎
def create(
self,
assign_layout: bool = True
) -> None
Create the ids, app charts, layout, callbacks, and optional modules.
Parameters:
| Name | Description |
|---|---|
| assign_layout | if True, will assign self.app.layout. If False, must call self.return_layout separately.Default is True |
Raises:
| Type | Description |
|---|---|
| NotImplementedError | if child class has not set the self.name data member |
View Source
def create(self, assign_layout: bool = True) -> None: # noqa: CCR001
"""Create the ids, app charts, layout, callbacks, and optional modules.
Args:
assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
Default is True
Raises:
NotImplementedError: if child class has not set the `self.name` data member
"""
if self.name is None: # pragma: no cover
raise NotImplementedError('Child class must set `self.name` to a unique string for this app')
# Initialize app and each module
self.initialization()
for mod in self.modules:
self.register_uniq_ids(mod.all_ids)
self.override_module_defaults() # Call optional override method
# Create charts for app and each module
self.create_elements()
for mod in self.modules:
mod.create_elements(self._il)
# Create app layout. User must call the return_layout method from each module within own return_layout method
if assign_layout:
self.app.layout = self.return_layout()
if assign_layout and self.validation_layout:
self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
pprint('\n\nValidationLayout?')
pprint(self.app.validation_layout)
# Create callbacks for app and each module
self.create_callbacks()
for mod in self.modules:
mod.create_callbacks(self)
self.verify_app_initialization()
create_callbacks⚓︎
def create_callbacks(
self
) -> None
Register callbacks necessary for this tab.
View Source
def create_callbacks(self) -> None:
"""Register callbacks necessary for this tab."""
self.verify_types_for_callbacks()
self.register_update_chart()
create_elements⚓︎
def create_elements(
self
) -> None
Initialize the charts, tables, and other Dash elements.
View Source
def create_elements(self) -> None:
"""Initialize the charts, tables, and other Dash elements."""
...
generate_data⚓︎
def generate_data(
self
) -> None
Recommended method for generating data stored in memory. Called in initialization.
View Source
def generate_data(self) -> None:
"""Recommended method for generating data stored in memory. Called in initialization."""
...
get_server⚓︎
def get_server(
self
)
Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
| Type | Description |
|---|---|
| dict | the Flask server component of the Dash app |
View Source
def get_server(self):
"""Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
dict: the Flask `server` component of the Dash app
"""
return self.app.server
initialization⚓︎
def initialization(
self
) -> None
Initialize ids with self.register_uniq_ids([...]) and other one-time actions.
View Source
def initialization(self) -> None:
"""Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
super().initialization()
# Register the the unique element IDs
self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
self.register_uniq_ids([self.id_chart] + self.input_ids)
# Configure the options for the various dropdowns
self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
self.t_opts = tuple(opts_dd(template, template) for template in self.templates)
override_module_defaults⚓︎
def override_module_defaults(
self
) -> None
Override default values from modules.
View Source
def override_module_defaults(self) -> None:
"""Override default values from modules."""
...
register_uniq_ids⚓︎
def register_uniq_ids(
self,
app_ids: List[str]
) -> None
Register the app_ids to the corresponding global_id in the self._il lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers self._il
which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Parameters:
| Name | Description |
|---|---|
| app_ids | list of strings that are unique within this App |
View Source
def register_uniq_ids(self, app_ids: List[str]) -> None:
"""Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Args:
app_ids: list of strings that are unique within this App
"""
self._il = deepcopy(self._il)
for app_id in app_ids:
self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')
register_update_chart⚓︎
def register_update_chart(
self
)
Register the update_chart callback.
View Source
def register_update_chart(self): # noqa: CCR001
"""Register the update_chart callback."""
outputs = [(self.id_chart, 'figure')]
inputs = [(_id, 'value') for _id in self.input_ids]
states = ()
@self.callback(outputs, inputs, states)
def update_chart(*raw_args):
a_in, _a_states = map_args(raw_args, inputs, states)
name_func = a_in[self.id_func]['value']
properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
new_chart = {}
# If event is not a tab change, return the updated chart
if 'tabs-select.value' not in properties: # FIXME: replace tabs-select with actual keyname (?)
if self.takes_args:
# Parse the arguments to generate a new plot
kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
else:
new_chart = self.func_map[name_func]()
# Example Mapping Output. Alternatively, just: `return [new_chart]`
return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])
return_layout⚓︎
def return_layout(
self
) -> dict
Return Dash application layout.
Returns:
| Type | Description |
|---|---|
| dict | Dash HTML object |
View Source
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
self.verify_types_for_layout()
return html.Div(
[ # noqa: ECE001
html.Div(
[
dropdown_group(
'Plot Type:', self._il[self.id_func],
self.func_opts, value=self.func_opts[0]['label'],
),
dropdown_group(
'Template:', self._il[self.id_template],
self.t_opts, value=self.t_opts[0]['label'],
),
] + [
dropdown_group(
f'{dim}:', self._il[dim], self.col_opts,
value=self.default_dim_name.get(dim, None),
)
for dim in self.dims
] + [
dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
for dim, items in self.dims_dict.items()
], style={'width': '25%', 'float': 'left'},
),
min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
], style={'padding': '15px'},
)
run⚓︎
def run(
self,
**dash_kwargs: dict
) -> None
Launch the Dash server instance.
Parameters:
| Name | Description |
|---|---|
| **dash_kwargs | keyword arguments for Dash.run_server() |
View Source
def run(self, **dash_kwargs: dict) -> None:
"""Launch the Dash server instance.
Args:
**dash_kwargs: keyword arguments for `Dash.run_server()`
"""
self.app.run_server(**dash_kwargs) # pragma: no cover
verify_app_initialization⚓︎
def verify_app_initialization(
self
) -> None
Check that the app was properly initialized.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if child class has not called self.register_uniq_ids |
View Source
def verify_app_initialization(self) -> None:
"""Check that the app was properly initialized.
Raises:
RuntimeError: if child class has not called `self.register_uniq_ids`
"""
if not self._il.keys(): # pragma: no cover
raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')
verify_types_for_callbacks⚓︎
def verify_types_for_callbacks(
self
)
Verify data types of data members necessary for the callbacks of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_callbacks(self):
"""Verify data types of data members necessary for the callbacks of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.takes_args, bool):
errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
if not (isinstance(self.data, pd.DataFrame) or self.data is None):
errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
if not isinstance(self.func_map, OrderedDict):
errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
verify_types_for_layout⚓︎
def verify_types_for_layout(
self
)
Verify data types of data members necessary for the layout of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_layout(self):
"""Verify data types of data members necessary for the layout of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.name, str):
errors.append(f'Expected self.name="{self.name}" to be str')
if not isinstance(self.dims, tuple):
errors.append(f'Expected self.dims="{self.dims}" to be tuple')
if not isinstance(self.dims_dict, OrderedDict):
errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
TabGapminder⚓︎
class TabGapminder(
app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabGapminder(TabBase):
"""TabGapminder properties."""
name = 'Gapminder Data'
data = px.data.gapminder()
func_map = OrderedDict([
('area', px.area),
('line', px.line),
])
dims = ('x', 'y', 'color', 'line_group', 'facet_row', 'facet_col')
default_dim_name = {
'x': 'year',
'y': 'pop',
'color': 'continent',
'line_group': 'country',
}
Ancestors (in MRO)⚓︎
- dash_charts.app_px.TabBase
- dash_charts.utils_app.AppBase
Class variables⚓︎
data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout
Methods⚓︎
callback⚓︎
def callback(
self,
outputs,
inputs,
states,
pic: bool = False,
**kwargs: dict
)
Return app callback decorator based on provided components.
Parameters:
| Name | Description |
|---|---|
| outputs | list of tuples with app_id and property name |
| inputs | list of tuples with app_id and property name |
| states | list of tuples with app_id and property name |
| pic | If True, prevent call on page load (prevent_initial_call). Default is False |
| **kwargs | any additional keyword arguments for self.app.callback |
Returns:
| Type | Description |
|---|---|
| dict | result of self.app.callback() |
View Source
def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
"""Return app callback decorator based on provided components.
Args:
outputs: list of tuples with app_id and property name
inputs: list of tuples with app_id and property name
states: list of tuples with app_id and property name
pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
**kwargs: any additional keyword arguments for `self.app.callback`
Returns:
dict: result of `self.app.callback()`
"""
return self.app.callback(
*format_app_callback(self._il, outputs, inputs, states),
prevent_initial_call=pic,
**kwargs,
)
create⚓︎
def create(
self,
assign_layout: bool = True
) -> None
Create the ids, app charts, layout, callbacks, and optional modules.
Parameters:
| Name | Description |
|---|---|
| assign_layout | if True, will assign self.app.layout. If False, must call self.return_layout separately.Default is True |
Raises:
| Type | Description |
|---|---|
| NotImplementedError | if child class has not set the self.name data member |
View Source
def create(self, assign_layout: bool = True) -> None: # noqa: CCR001
"""Create the ids, app charts, layout, callbacks, and optional modules.
Args:
assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
Default is True
Raises:
NotImplementedError: if child class has not set the `self.name` data member
"""
if self.name is None: # pragma: no cover
raise NotImplementedError('Child class must set `self.name` to a unique string for this app')
# Initialize app and each module
self.initialization()
for mod in self.modules:
self.register_uniq_ids(mod.all_ids)
self.override_module_defaults() # Call optional override method
# Create charts for app and each module
self.create_elements()
for mod in self.modules:
mod.create_elements(self._il)
# Create app layout. User must call the return_layout method from each module within own return_layout method
if assign_layout:
self.app.layout = self.return_layout()
if assign_layout and self.validation_layout:
self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
pprint('\n\nValidationLayout?')
pprint(self.app.validation_layout)
# Create callbacks for app and each module
self.create_callbacks()
for mod in self.modules:
mod.create_callbacks(self)
self.verify_app_initialization()
create_callbacks⚓︎
def create_callbacks(
self
) -> None
Register callbacks necessary for this tab.
View Source
def create_callbacks(self) -> None:
"""Register callbacks necessary for this tab."""
self.verify_types_for_callbacks()
self.register_update_chart()
create_elements⚓︎
def create_elements(
self
) -> None
Initialize the charts, tables, and other Dash elements.
View Source
def create_elements(self) -> None:
"""Initialize the charts, tables, and other Dash elements."""
...
generate_data⚓︎
def generate_data(
self
) -> None
Recommended method for generating data stored in memory. Called in initialization.
View Source
def generate_data(self) -> None:
"""Recommended method for generating data stored in memory. Called in initialization."""
...
get_server⚓︎
def get_server(
self
)
Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
| Type | Description |
|---|---|
| dict | the Flask server component of the Dash app |
View Source
def get_server(self):
"""Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
dict: the Flask `server` component of the Dash app
"""
return self.app.server
initialization⚓︎
def initialization(
self
) -> None
Initialize ids with self.register_uniq_ids([...]) and other one-time actions.
View Source
def initialization(self) -> None:
"""Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
super().initialization()
# Register the the unique element IDs
self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
self.register_uniq_ids([self.id_chart] + self.input_ids)
# Configure the options for the various dropdowns
self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
self.t_opts = tuple(opts_dd(template, template) for template in self.templates)
override_module_defaults⚓︎
def override_module_defaults(
self
) -> None
Override default values from modules.
View Source
def override_module_defaults(self) -> None:
"""Override default values from modules."""
...
register_uniq_ids⚓︎
def register_uniq_ids(
self,
app_ids: List[str]
) -> None
Register the app_ids to the corresponding global_id in the self._il lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers self._il
which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Parameters:
| Name | Description |
|---|---|
| app_ids | list of strings that are unique within this App |
View Source
def register_uniq_ids(self, app_ids: List[str]) -> None:
"""Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Args:
app_ids: list of strings that are unique within this App
"""
self._il = deepcopy(self._il)
for app_id in app_ids:
self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')
register_update_chart⚓︎
def register_update_chart(
self
)
Register the update_chart callback.
View Source
def register_update_chart(self): # noqa: CCR001
"""Register the update_chart callback."""
outputs = [(self.id_chart, 'figure')]
inputs = [(_id, 'value') for _id in self.input_ids]
states = ()
@self.callback(outputs, inputs, states)
def update_chart(*raw_args):
a_in, _a_states = map_args(raw_args, inputs, states)
name_func = a_in[self.id_func]['value']
properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
new_chart = {}
# If event is not a tab change, return the updated chart
if 'tabs-select.value' not in properties: # FIXME: replace tabs-select with actual keyname (?)
if self.takes_args:
# Parse the arguments to generate a new plot
kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
else:
new_chart = self.func_map[name_func]()
# Example Mapping Output. Alternatively, just: `return [new_chart]`
return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])
return_layout⚓︎
def return_layout(
self
) -> dict
Return Dash application layout.
Returns:
| Type | Description |
|---|---|
| dict | Dash HTML object |
View Source
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
self.verify_types_for_layout()
return html.Div(
[ # noqa: ECE001
html.Div(
[
dropdown_group(
'Plot Type:', self._il[self.id_func],
self.func_opts, value=self.func_opts[0]['label'],
),
dropdown_group(
'Template:', self._il[self.id_template],
self.t_opts, value=self.t_opts[0]['label'],
),
] + [
dropdown_group(
f'{dim}:', self._il[dim], self.col_opts,
value=self.default_dim_name.get(dim, None),
)
for dim in self.dims
] + [
dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
for dim, items in self.dims_dict.items()
], style={'width': '25%', 'float': 'left'},
),
min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
], style={'padding': '15px'},
)
run⚓︎
def run(
self,
**dash_kwargs: dict
) -> None
Launch the Dash server instance.
Parameters:
| Name | Description |
|---|---|
| **dash_kwargs | keyword arguments for Dash.run_server() |
View Source
def run(self, **dash_kwargs: dict) -> None:
"""Launch the Dash server instance.
Args:
**dash_kwargs: keyword arguments for `Dash.run_server()`
"""
self.app.run_server(**dash_kwargs) # pragma: no cover
verify_app_initialization⚓︎
def verify_app_initialization(
self
) -> None
Check that the app was properly initialized.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if child class has not called self.register_uniq_ids |
View Source
def verify_app_initialization(self) -> None:
"""Check that the app was properly initialized.
Raises:
RuntimeError: if child class has not called `self.register_uniq_ids`
"""
if not self._il.keys(): # pragma: no cover
raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')
verify_types_for_callbacks⚓︎
def verify_types_for_callbacks(
self
)
Verify data types of data members necessary for the callbacks of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_callbacks(self):
"""Verify data types of data members necessary for the callbacks of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.takes_args, bool):
errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
if not (isinstance(self.data, pd.DataFrame) or self.data is None):
errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
if not isinstance(self.func_map, OrderedDict):
errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
verify_types_for_layout⚓︎
def verify_types_for_layout(
self
)
Verify data types of data members necessary for the layout of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_layout(self):
"""Verify data types of data members necessary for the layout of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.name, str):
errors.append(f'Expected self.name="{self.name}" to be str')
if not isinstance(self.dims, tuple):
errors.append(f'Expected self.dims="{self.dims}" to be tuple')
if not isinstance(self.dims_dict, OrderedDict):
errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
TabIris⚓︎
class TabIris(
app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabIris(TabBase):
"""TabIris properties."""
name = 'Iris Data'
data = px.data.iris()
func_map = OrderedDict([
('histogram', px.histogram),
('bar', px.bar),
('strip', px.strip),
('box', px.box),
('violin', px.violin),
])
dims = ('x', 'y', 'color', 'facet_row', 'facet_col')
default_dim_name = {
'x': 'sepal_width',
'color': 'species',
}
Ancestors (in MRO)⚓︎
- dash_charts.app_px.TabBase
- dash_charts.utils_app.AppBase
Class variables⚓︎
data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout
Methods⚓︎
callback⚓︎
def callback(
self,
outputs,
inputs,
states,
pic: bool = False,
**kwargs: dict
)
Return app callback decorator based on provided components.
Parameters:
| Name | Description |
|---|---|
| outputs | list of tuples with app_id and property name |
| inputs | list of tuples with app_id and property name |
| states | list of tuples with app_id and property name |
| pic | If True, prevent call on page load (prevent_initial_call). Default is False |
| **kwargs | any additional keyword arguments for self.app.callback |
Returns:
| Type | Description |
|---|---|
| dict | result of self.app.callback() |
View Source
def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
"""Return app callback decorator based on provided components.
Args:
outputs: list of tuples with app_id and property name
inputs: list of tuples with app_id and property name
states: list of tuples with app_id and property name
pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
**kwargs: any additional keyword arguments for `self.app.callback`
Returns:
dict: result of `self.app.callback()`
"""
return self.app.callback(
*format_app_callback(self._il, outputs, inputs, states),
prevent_initial_call=pic,
**kwargs,
)
create⚓︎
def create(
self,
assign_layout: bool = True
) -> None
Create the ids, app charts, layout, callbacks, and optional modules.
Parameters:
| Name | Description |
|---|---|
| assign_layout | if True, will assign self.app.layout. If False, must call self.return_layout separately.Default is True |
Raises:
| Type | Description |
|---|---|
| NotImplementedError | if child class has not set the self.name data member |
View Source
def create(self, assign_layout: bool = True) -> None: # noqa: CCR001
"""Create the ids, app charts, layout, callbacks, and optional modules.
Args:
assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
Default is True
Raises:
NotImplementedError: if child class has not set the `self.name` data member
"""
if self.name is None: # pragma: no cover
raise NotImplementedError('Child class must set `self.name` to a unique string for this app')
# Initialize app and each module
self.initialization()
for mod in self.modules:
self.register_uniq_ids(mod.all_ids)
self.override_module_defaults() # Call optional override method
# Create charts for app and each module
self.create_elements()
for mod in self.modules:
mod.create_elements(self._il)
# Create app layout. User must call the return_layout method from each module within own return_layout method
if assign_layout:
self.app.layout = self.return_layout()
if assign_layout and self.validation_layout:
self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
pprint('\n\nValidationLayout?')
pprint(self.app.validation_layout)
# Create callbacks for app and each module
self.create_callbacks()
for mod in self.modules:
mod.create_callbacks(self)
self.verify_app_initialization()
create_callbacks⚓︎
def create_callbacks(
self
) -> None
Register callbacks necessary for this tab.
View Source
def create_callbacks(self) -> None:
"""Register callbacks necessary for this tab."""
self.verify_types_for_callbacks()
self.register_update_chart()
create_elements⚓︎
def create_elements(
self
) -> None
Initialize the charts, tables, and other Dash elements.
View Source
def create_elements(self) -> None:
"""Initialize the charts, tables, and other Dash elements."""
...
generate_data⚓︎
def generate_data(
self
) -> None
Recommended method for generating data stored in memory. Called in initialization.
View Source
def generate_data(self) -> None:
"""Recommended method for generating data stored in memory. Called in initialization."""
...
get_server⚓︎
def get_server(
self
)
Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
| Type | Description |
|---|---|
| dict | the Flask server component of the Dash app |
View Source
def get_server(self):
"""Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
dict: the Flask `server` component of the Dash app
"""
return self.app.server
initialization⚓︎
def initialization(
self
) -> None
Initialize ids with self.register_uniq_ids([...]) and other one-time actions.
View Source
def initialization(self) -> None:
"""Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
super().initialization()
# Register the the unique element IDs
self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
self.register_uniq_ids([self.id_chart] + self.input_ids)
# Configure the options for the various dropdowns
self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
self.t_opts = tuple(opts_dd(template, template) for template in self.templates)
override_module_defaults⚓︎
def override_module_defaults(
self
) -> None
Override default values from modules.
View Source
def override_module_defaults(self) -> None:
"""Override default values from modules."""
...
register_uniq_ids⚓︎
def register_uniq_ids(
self,
app_ids: List[str]
) -> None
Register the app_ids to the corresponding global_id in the self._il lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers self._il
which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Parameters:
| Name | Description |
|---|---|
| app_ids | list of strings that are unique within this App |
View Source
def register_uniq_ids(self, app_ids: List[str]) -> None:
"""Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Args:
app_ids: list of strings that are unique within this App
"""
self._il = deepcopy(self._il)
for app_id in app_ids:
self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')
register_update_chart⚓︎
def register_update_chart(
self
)
Register the update_chart callback.
View Source
def register_update_chart(self): # noqa: CCR001
"""Register the update_chart callback."""
outputs = [(self.id_chart, 'figure')]
inputs = [(_id, 'value') for _id in self.input_ids]
states = ()
@self.callback(outputs, inputs, states)
def update_chart(*raw_args):
a_in, _a_states = map_args(raw_args, inputs, states)
name_func = a_in[self.id_func]['value']
properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
new_chart = {}
# If event is not a tab change, return the updated chart
if 'tabs-select.value' not in properties: # FIXME: replace tabs-select with actual keyname (?)
if self.takes_args:
# Parse the arguments to generate a new plot
kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
else:
new_chart = self.func_map[name_func]()
# Example Mapping Output. Alternatively, just: `return [new_chart]`
return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])
return_layout⚓︎
def return_layout(
self
) -> dict
Return Dash application layout.
Returns:
| Type | Description |
|---|---|
| dict | Dash HTML object |
View Source
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
self.verify_types_for_layout()
return html.Div(
[ # noqa: ECE001
html.Div(
[
dropdown_group(
'Plot Type:', self._il[self.id_func],
self.func_opts, value=self.func_opts[0]['label'],
),
dropdown_group(
'Template:', self._il[self.id_template],
self.t_opts, value=self.t_opts[0]['label'],
),
] + [
dropdown_group(
f'{dim}:', self._il[dim], self.col_opts,
value=self.default_dim_name.get(dim, None),
)
for dim in self.dims
] + [
dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
for dim, items in self.dims_dict.items()
], style={'width': '25%', 'float': 'left'},
),
min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
], style={'padding': '15px'},
)
run⚓︎
def run(
self,
**dash_kwargs: dict
) -> None
Launch the Dash server instance.
Parameters:
| Name | Description |
|---|---|
| **dash_kwargs | keyword arguments for Dash.run_server() |
View Source
def run(self, **dash_kwargs: dict) -> None:
"""Launch the Dash server instance.
Args:
**dash_kwargs: keyword arguments for `Dash.run_server()`
"""
self.app.run_server(**dash_kwargs) # pragma: no cover
verify_app_initialization⚓︎
def verify_app_initialization(
self
) -> None
Check that the app was properly initialized.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if child class has not called self.register_uniq_ids |
View Source
def verify_app_initialization(self) -> None:
"""Check that the app was properly initialized.
Raises:
RuntimeError: if child class has not called `self.register_uniq_ids`
"""
if not self._il.keys(): # pragma: no cover
raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')
verify_types_for_callbacks⚓︎
def verify_types_for_callbacks(
self
)
Verify data types of data members necessary for the callbacks of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_callbacks(self):
"""Verify data types of data members necessary for the callbacks of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.takes_args, bool):
errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
if not (isinstance(self.data, pd.DataFrame) or self.data is None):
errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
if not isinstance(self.func_map, OrderedDict):
errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
verify_types_for_layout⚓︎
def verify_types_for_layout(
self
)
Verify data types of data members necessary for the layout of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_layout(self):
"""Verify data types of data members necessary for the layout of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.name, str):
errors.append(f'Expected self.name="{self.name}" to be str')
if not isinstance(self.dims, tuple):
errors.append(f'Expected self.dims="{self.dims}" to be tuple')
if not isinstance(self.dims_dict, OrderedDict):
errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
TabTernary⚓︎
class TabTernary(
app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabTernary(TabBase):
"""TabTernary properties."""
name = 'Ternary'
data = px.data.election()
func_map = OrderedDict([
('scatter_ternary', px.scatter_ternary),
('line_ternary', px.line_ternary),
])
dims = ('a', 'b', 'c', 'color', 'hover_name') # size - only for scatter
default_dim_name = {
'a': 'Joly',
'b': 'Coderre',
'c': 'Bergeron',
'color': 'winner',
'hover_name': 'district',
}
Ancestors (in MRO)⚓︎
- dash_charts.app_px.TabBase
- dash_charts.utils_app.AppBase
Class variables⚓︎
data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout
Methods⚓︎
callback⚓︎
def callback(
self,
outputs,
inputs,
states,
pic: bool = False,
**kwargs: dict
)
Return app callback decorator based on provided components.
Parameters:
| Name | Description |
|---|---|
| outputs | list of tuples with app_id and property name |
| inputs | list of tuples with app_id and property name |
| states | list of tuples with app_id and property name |
| pic | If True, prevent call on page load (prevent_initial_call). Default is False |
| **kwargs | any additional keyword arguments for self.app.callback |
Returns:
| Type | Description |
|---|---|
| dict | result of self.app.callback() |
View Source
def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
"""Return app callback decorator based on provided components.
Args:
outputs: list of tuples with app_id and property name
inputs: list of tuples with app_id and property name
states: list of tuples with app_id and property name
pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
**kwargs: any additional keyword arguments for `self.app.callback`
Returns:
dict: result of `self.app.callback()`
"""
return self.app.callback(
*format_app_callback(self._il, outputs, inputs, states),
prevent_initial_call=pic,
**kwargs,
)
create⚓︎
def create(
self,
assign_layout: bool = True
) -> None
Create the ids, app charts, layout, callbacks, and optional modules.
Parameters:
| Name | Description |
|---|---|
| assign_layout | if True, will assign self.app.layout. If False, must call self.return_layout separately.Default is True |
Raises:
| Type | Description |
|---|---|
| NotImplementedError | if child class has not set the self.name data member |
View Source
def create(self, assign_layout: bool = True) -> None: # noqa: CCR001
"""Create the ids, app charts, layout, callbacks, and optional modules.
Args:
assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
Default is True
Raises:
NotImplementedError: if child class has not set the `self.name` data member
"""
if self.name is None: # pragma: no cover
raise NotImplementedError('Child class must set `self.name` to a unique string for this app')
# Initialize app and each module
self.initialization()
for mod in self.modules:
self.register_uniq_ids(mod.all_ids)
self.override_module_defaults() # Call optional override method
# Create charts for app and each module
self.create_elements()
for mod in self.modules:
mod.create_elements(self._il)
# Create app layout. User must call the return_layout method from each module within own return_layout method
if assign_layout:
self.app.layout = self.return_layout()
if assign_layout and self.validation_layout:
self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
pprint('\n\nValidationLayout?')
pprint(self.app.validation_layout)
# Create callbacks for app and each module
self.create_callbacks()
for mod in self.modules:
mod.create_callbacks(self)
self.verify_app_initialization()
create_callbacks⚓︎
def create_callbacks(
self
) -> None
Register callbacks necessary for this tab.
View Source
def create_callbacks(self) -> None:
"""Register callbacks necessary for this tab."""
self.verify_types_for_callbacks()
self.register_update_chart()
create_elements⚓︎
def create_elements(
self
) -> None
Initialize the charts, tables, and other Dash elements.
View Source
def create_elements(self) -> None:
"""Initialize the charts, tables, and other Dash elements."""
...
generate_data⚓︎
def generate_data(
self
) -> None
Recommended method for generating data stored in memory. Called in initialization.
View Source
def generate_data(self) -> None:
"""Recommended method for generating data stored in memory. Called in initialization."""
...
get_server⚓︎
def get_server(
self
)
Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
| Type | Description |
|---|---|
| dict | the Flask server component of the Dash app |
View Source
def get_server(self):
"""Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
dict: the Flask `server` component of the Dash app
"""
return self.app.server
initialization⚓︎
def initialization(
self
) -> None
Initialize ids with self.register_uniq_ids([...]) and other one-time actions.
View Source
def initialization(self) -> None:
"""Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
super().initialization()
# Register the the unique element IDs
self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
self.register_uniq_ids([self.id_chart] + self.input_ids)
# Configure the options for the various dropdowns
self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
self.t_opts = tuple(opts_dd(template, template) for template in self.templates)
override_module_defaults⚓︎
def override_module_defaults(
self
) -> None
Override default values from modules.
View Source
def override_module_defaults(self) -> None:
"""Override default values from modules."""
...
register_uniq_ids⚓︎
def register_uniq_ids(
self,
app_ids: List[str]
) -> None
Register the app_ids to the corresponding global_id in the self._il lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers self._il
which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Parameters:
| Name | Description |
|---|---|
| app_ids | list of strings that are unique within this App |
View Source
def register_uniq_ids(self, app_ids: List[str]) -> None:
"""Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Args:
app_ids: list of strings that are unique within this App
"""
self._il = deepcopy(self._il)
for app_id in app_ids:
self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')
register_update_chart⚓︎
def register_update_chart(
self
)
Register the update_chart callback.
View Source
def register_update_chart(self): # noqa: CCR001
"""Register the update_chart callback."""
outputs = [(self.id_chart, 'figure')]
inputs = [(_id, 'value') for _id in self.input_ids]
states = ()
@self.callback(outputs, inputs, states)
def update_chart(*raw_args):
a_in, _a_states = map_args(raw_args, inputs, states)
name_func = a_in[self.id_func]['value']
properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
new_chart = {}
# If event is not a tab change, return the updated chart
if 'tabs-select.value' not in properties: # FIXME: replace tabs-select with actual keyname (?)
if self.takes_args:
# Parse the arguments to generate a new plot
kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
else:
new_chart = self.func_map[name_func]()
# Example Mapping Output. Alternatively, just: `return [new_chart]`
return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])
return_layout⚓︎
def return_layout(
self
) -> dict
Return Dash application layout.
Returns:
| Type | Description |
|---|---|
| dict | Dash HTML object |
View Source
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
self.verify_types_for_layout()
return html.Div(
[ # noqa: ECE001
html.Div(
[
dropdown_group(
'Plot Type:', self._il[self.id_func],
self.func_opts, value=self.func_opts[0]['label'],
),
dropdown_group(
'Template:', self._il[self.id_template],
self.t_opts, value=self.t_opts[0]['label'],
),
] + [
dropdown_group(
f'{dim}:', self._il[dim], self.col_opts,
value=self.default_dim_name.get(dim, None),
)
for dim in self.dims
] + [
dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
for dim, items in self.dims_dict.items()
], style={'width': '25%', 'float': 'left'},
),
min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
], style={'padding': '15px'},
)
run⚓︎
def run(
self,
**dash_kwargs: dict
) -> None
Launch the Dash server instance.
Parameters:
| Name | Description |
|---|---|
| **dash_kwargs | keyword arguments for Dash.run_server() |
View Source
def run(self, **dash_kwargs: dict) -> None:
"""Launch the Dash server instance.
Args:
**dash_kwargs: keyword arguments for `Dash.run_server()`
"""
self.app.run_server(**dash_kwargs) # pragma: no cover
verify_app_initialization⚓︎
def verify_app_initialization(
self
) -> None
Check that the app was properly initialized.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if child class has not called self.register_uniq_ids |
View Source
def verify_app_initialization(self) -> None:
"""Check that the app was properly initialized.
Raises:
RuntimeError: if child class has not called `self.register_uniq_ids`
"""
if not self._il.keys(): # pragma: no cover
raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')
verify_types_for_callbacks⚓︎
def verify_types_for_callbacks(
self
)
Verify data types of data members necessary for the callbacks of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_callbacks(self):
"""Verify data types of data members necessary for the callbacks of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.takes_args, bool):
errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
if not (isinstance(self.data, pd.DataFrame) or self.data is None):
errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
if not isinstance(self.func_map, OrderedDict):
errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
verify_types_for_layout⚓︎
def verify_types_for_layout(
self
)
Verify data types of data members necessary for the layout of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_layout(self):
"""Verify data types of data members necessary for the layout of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.name, str):
errors.append(f'Expected self.name="{self.name}" to be str')
if not isinstance(self.dims, tuple):
errors.append(f'Expected self.dims="{self.dims}" to be tuple')
if not isinstance(self.dims_dict, OrderedDict):
errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
TabTip⚓︎
class TabTip(
app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabTip(TabBase):
"""TabTip properties."""
name = 'Tip Data'
data = px.data.tips()
func_map = OrderedDict([
('scatter', px.scatter),
('density_contour', px.density_contour),
])
dims = ('x', 'y', 'color', 'facet_row', 'facet_col')
dims_dict = OrderedDict([
('marginal_x', ('histogram', 'rag', 'violin', 'box')),
('marginal_y', ('histogram', 'rag', 'violin', 'box')),
('trendline', ('ols', 'lowess')),
])
default_dim_name = {
'x': 'total_bill',
'y': 'tip',
'color': 'smoker',
}
Ancestors (in MRO)⚓︎
- dash_charts.app_px.TabBase
- dash_charts.utils_app.AppBase
Class variables⚓︎
data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout
Methods⚓︎
callback⚓︎
def callback(
self,
outputs,
inputs,
states,
pic: bool = False,
**kwargs: dict
)
Return app callback decorator based on provided components.
Parameters:
| Name | Description |
|---|---|
| outputs | list of tuples with app_id and property name |
| inputs | list of tuples with app_id and property name |
| states | list of tuples with app_id and property name |
| pic | If True, prevent call on page load (prevent_initial_call). Default is False |
| **kwargs | any additional keyword arguments for self.app.callback |
Returns:
| Type | Description |
|---|---|
| dict | result of self.app.callback() |
View Source
def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
"""Return app callback decorator based on provided components.
Args:
outputs: list of tuples with app_id and property name
inputs: list of tuples with app_id and property name
states: list of tuples with app_id and property name
pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
**kwargs: any additional keyword arguments for `self.app.callback`
Returns:
dict: result of `self.app.callback()`
"""
return self.app.callback(
*format_app_callback(self._il, outputs, inputs, states),
prevent_initial_call=pic,
**kwargs,
)
create⚓︎
def create(
self,
assign_layout: bool = True
) -> None
Create the ids, app charts, layout, callbacks, and optional modules.
Parameters:
| Name | Description |
|---|---|
| assign_layout | if True, will assign self.app.layout. If False, must call self.return_layout separately.Default is True |
Raises:
| Type | Description |
|---|---|
| NotImplementedError | if child class has not set the self.name data member |
View Source
def create(self, assign_layout: bool = True) -> None: # noqa: CCR001
"""Create the ids, app charts, layout, callbacks, and optional modules.
Args:
assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
Default is True
Raises:
NotImplementedError: if child class has not set the `self.name` data member
"""
if self.name is None: # pragma: no cover
raise NotImplementedError('Child class must set `self.name` to a unique string for this app')
# Initialize app and each module
self.initialization()
for mod in self.modules:
self.register_uniq_ids(mod.all_ids)
self.override_module_defaults() # Call optional override method
# Create charts for app and each module
self.create_elements()
for mod in self.modules:
mod.create_elements(self._il)
# Create app layout. User must call the return_layout method from each module within own return_layout method
if assign_layout:
self.app.layout = self.return_layout()
if assign_layout and self.validation_layout:
self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
pprint('\n\nValidationLayout?')
pprint(self.app.validation_layout)
# Create callbacks for app and each module
self.create_callbacks()
for mod in self.modules:
mod.create_callbacks(self)
self.verify_app_initialization()
create_callbacks⚓︎
def create_callbacks(
self
) -> None
Register callbacks necessary for this tab.
View Source
def create_callbacks(self) -> None:
"""Register callbacks necessary for this tab."""
self.verify_types_for_callbacks()
self.register_update_chart()
create_elements⚓︎
def create_elements(
self
) -> None
Initialize the charts, tables, and other Dash elements.
View Source
def create_elements(self) -> None:
"""Initialize the charts, tables, and other Dash elements."""
...
generate_data⚓︎
def generate_data(
self
) -> None
Recommended method for generating data stored in memory. Called in initialization.
View Source
def generate_data(self) -> None:
"""Recommended method for generating data stored in memory. Called in initialization."""
...
get_server⚓︎
def get_server(
self
)
Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
| Type | Description |
|---|---|
| dict | the Flask server component of the Dash app |
View Source
def get_server(self):
"""Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
dict: the Flask `server` component of the Dash app
"""
return self.app.server
initialization⚓︎
def initialization(
self
) -> None
Initialize ids with self.register_uniq_ids([...]) and other one-time actions.
View Source
def initialization(self) -> None:
"""Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
super().initialization()
# Register the the unique element IDs
self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
self.register_uniq_ids([self.id_chart] + self.input_ids)
# Configure the options for the various dropdowns
self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
self.t_opts = tuple(opts_dd(template, template) for template in self.templates)
override_module_defaults⚓︎
def override_module_defaults(
self
) -> None
Override default values from modules.
View Source
def override_module_defaults(self) -> None:
"""Override default values from modules."""
...
register_uniq_ids⚓︎
def register_uniq_ids(
self,
app_ids: List[str]
) -> None
Register the app_ids to the corresponding global_id in the self._il lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers self._il
which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Parameters:
| Name | Description |
|---|---|
| app_ids | list of strings that are unique within this App |
View Source
def register_uniq_ids(self, app_ids: List[str]) -> None:
"""Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Args:
app_ids: list of strings that are unique within this App
"""
self._il = deepcopy(self._il)
for app_id in app_ids:
self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')
register_update_chart⚓︎
def register_update_chart(
self
)
Register the update_chart callback.
View Source
def register_update_chart(self): # noqa: CCR001
"""Register the update_chart callback."""
outputs = [(self.id_chart, 'figure')]
inputs = [(_id, 'value') for _id in self.input_ids]
states = ()
@self.callback(outputs, inputs, states)
def update_chart(*raw_args):
a_in, _a_states = map_args(raw_args, inputs, states)
name_func = a_in[self.id_func]['value']
properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
new_chart = {}
# If event is not a tab change, return the updated chart
if 'tabs-select.value' not in properties: # FIXME: replace tabs-select with actual keyname (?)
if self.takes_args:
# Parse the arguments to generate a new plot
kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
else:
new_chart = self.func_map[name_func]()
# Example Mapping Output. Alternatively, just: `return [new_chart]`
return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])
return_layout⚓︎
def return_layout(
self
) -> dict
Return Dash application layout.
Returns:
| Type | Description |
|---|---|
| dict | Dash HTML object |
View Source
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
self.verify_types_for_layout()
return html.Div(
[ # noqa: ECE001
html.Div(
[
dropdown_group(
'Plot Type:', self._il[self.id_func],
self.func_opts, value=self.func_opts[0]['label'],
),
dropdown_group(
'Template:', self._il[self.id_template],
self.t_opts, value=self.t_opts[0]['label'],
),
] + [
dropdown_group(
f'{dim}:', self._il[dim], self.col_opts,
value=self.default_dim_name.get(dim, None),
)
for dim in self.dims
] + [
dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
for dim, items in self.dims_dict.items()
], style={'width': '25%', 'float': 'left'},
),
min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
], style={'padding': '15px'},
)
run⚓︎
def run(
self,
**dash_kwargs: dict
) -> None
Launch the Dash server instance.
Parameters:
| Name | Description |
|---|---|
| **dash_kwargs | keyword arguments for Dash.run_server() |
View Source
def run(self, **dash_kwargs: dict) -> None:
"""Launch the Dash server instance.
Args:
**dash_kwargs: keyword arguments for `Dash.run_server()`
"""
self.app.run_server(**dash_kwargs) # pragma: no cover
verify_app_initialization⚓︎
def verify_app_initialization(
self
) -> None
Check that the app was properly initialized.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if child class has not called self.register_uniq_ids |
View Source
def verify_app_initialization(self) -> None:
"""Check that the app was properly initialized.
Raises:
RuntimeError: if child class has not called `self.register_uniq_ids`
"""
if not self._il.keys(): # pragma: no cover
raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')
verify_types_for_callbacks⚓︎
def verify_types_for_callbacks(
self
)
Verify data types of data members necessary for the callbacks of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_callbacks(self):
"""Verify data types of data members necessary for the callbacks of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.takes_args, bool):
errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
if not (isinstance(self.data, pd.DataFrame) or self.data is None):
errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
if not isinstance(self.func_map, OrderedDict):
errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
verify_types_for_layout⚓︎
def verify_types_for_layout(
self
)
Verify data types of data members necessary for the layout of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_layout(self):
"""Verify data types of data members necessary for the layout of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.name, str):
errors.append(f'Expected self.name="{self.name}" to be str')
if not isinstance(self.dims, tuple):
errors.append(f'Expected self.dims="{self.dims}" to be tuple')
if not isinstance(self.dims_dict, OrderedDict):
errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
TabWind⚓︎
class TabWind(
app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class TabWind(TabBase):
"""TabWind properties."""
name = 'Wind'
data = px.data.wind()
func_map = OrderedDict([
('scatter_polar', px.scatter_polar),
('line_polar', px.line_polar), # (line_close=True)
('bar_polar', px.bar_polar),
])
dims = ('r', 'theta', 'color')
default_dim_name = {
'r': 'frequency',
'theta': 'direction',
'color': 'strength',
'symbol': 'strength',
}
Ancestors (in MRO)⚓︎
- dash_charts.app_px.TabBase
- dash_charts.utils_app.AppBase
Class variables⚓︎
data
default_dim_name
dims
dims_dict
external_stylesheets
func_map
id_chart
id_func
id_template
init_app_kwargs
modules
name
nsi
takes_args
templates
validation_layout
Methods⚓︎
callback⚓︎
def callback(
self,
outputs,
inputs,
states,
pic: bool = False,
**kwargs: dict
)
Return app callback decorator based on provided components.
Parameters:
| Name | Description |
|---|---|
| outputs | list of tuples with app_id and property name |
| inputs | list of tuples with app_id and property name |
| states | list of tuples with app_id and property name |
| pic | If True, prevent call on page load (prevent_initial_call). Default is False |
| **kwargs | any additional keyword arguments for self.app.callback |
Returns:
| Type | Description |
|---|---|
| dict | result of self.app.callback() |
View Source
def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
"""Return app callback decorator based on provided components.
Args:
outputs: list of tuples with app_id and property name
inputs: list of tuples with app_id and property name
states: list of tuples with app_id and property name
pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
**kwargs: any additional keyword arguments for `self.app.callback`
Returns:
dict: result of `self.app.callback()`
"""
return self.app.callback(
*format_app_callback(self._il, outputs, inputs, states),
prevent_initial_call=pic,
**kwargs,
)
create⚓︎
def create(
self,
assign_layout: bool = True
) -> None
Create the ids, app charts, layout, callbacks, and optional modules.
Parameters:
| Name | Description |
|---|---|
| assign_layout | if True, will assign self.app.layout. If False, must call self.return_layout separately.Default is True |
Raises:
| Type | Description |
|---|---|
| NotImplementedError | if child class has not set the self.name data member |
View Source
def create(self, assign_layout: bool = True) -> None: # noqa: CCR001
"""Create the ids, app charts, layout, callbacks, and optional modules.
Args:
assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
Default is True
Raises:
NotImplementedError: if child class has not set the `self.name` data member
"""
if self.name is None: # pragma: no cover
raise NotImplementedError('Child class must set `self.name` to a unique string for this app')
# Initialize app and each module
self.initialization()
for mod in self.modules:
self.register_uniq_ids(mod.all_ids)
self.override_module_defaults() # Call optional override method
# Create charts for app and each module
self.create_elements()
for mod in self.modules:
mod.create_elements(self._il)
# Create app layout. User must call the return_layout method from each module within own return_layout method
if assign_layout:
self.app.layout = self.return_layout()
if assign_layout and self.validation_layout:
self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
pprint('\n\nValidationLayout?')
pprint(self.app.validation_layout)
# Create callbacks for app and each module
self.create_callbacks()
for mod in self.modules:
mod.create_callbacks(self)
self.verify_app_initialization()
create_callbacks⚓︎
def create_callbacks(
self
) -> None
Register callbacks necessary for this tab.
View Source
def create_callbacks(self) -> None:
"""Register callbacks necessary for this tab."""
self.verify_types_for_callbacks()
self.register_update_chart()
create_elements⚓︎
def create_elements(
self
) -> None
Initialize the charts, tables, and other Dash elements.
View Source
def create_elements(self) -> None:
"""Initialize the charts, tables, and other Dash elements."""
...
generate_data⚓︎
def generate_data(
self
) -> None
Recommended method for generating data stored in memory. Called in initialization.
View Source
def generate_data(self) -> None:
"""Recommended method for generating data stored in memory. Called in initialization."""
...
get_server⚓︎
def get_server(
self
)
Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
| Type | Description |
|---|---|
| dict | the Flask server component of the Dash app |
View Source
def get_server(self):
"""Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.
Returns:
dict: the Flask `server` component of the Dash app
"""
return self.app.server
initialization⚓︎
def initialization(
self
) -> None
Initialize ids with self.register_uniq_ids([...]) and other one-time actions.
View Source
def initialization(self) -> None:
"""Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
super().initialization()
# Register the the unique element IDs
self.input_ids = [self.id_func, self.id_template] + [*self.dims] + [*self.dims_dict.keys()]
self.register_uniq_ids([self.id_chart] + self.input_ids)
# Configure the options for the various dropdowns
self.col_opts = [] if self.data is None else tuple(opts_dd(_c, _c) for _c in self.data.columns)
self.func_opts = tuple(opts_dd(lbl, lbl) for lbl in self.func_map.keys())
self.t_opts = tuple(opts_dd(template, template) for template in self.templates)
override_module_defaults⚓︎
def override_module_defaults(
self
) -> None
Override default values from modules.
View Source
def override_module_defaults(self) -> None:
"""Override default values from modules."""
...
register_uniq_ids⚓︎
def register_uniq_ids(
self,
app_ids: List[str]
) -> None
Register the app_ids to the corresponding global_id in the self._il lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers self._il
which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Parameters:
| Name | Description |
|---|---|
| app_ids | list of strings that are unique within this App |
View Source
def register_uniq_ids(self, app_ids: List[str]) -> None:
"""Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.
The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
class of this base App to be resused multiple times within a tabbed or multi-page application without
id-collision
Args:
app_ids: list of strings that are unique within this App
"""
self._il = deepcopy(self._il)
for app_id in app_ids:
self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')
register_update_chart⚓︎
def register_update_chart(
self
)
Register the update_chart callback.
View Source
def register_update_chart(self): # noqa: CCR001
"""Register the update_chart callback."""
outputs = [(self.id_chart, 'figure')]
inputs = [(_id, 'value') for _id in self.input_ids]
states = ()
@self.callback(outputs, inputs, states)
def update_chart(*raw_args):
a_in, _a_states = map_args(raw_args, inputs, states)
name_func = a_in[self.id_func]['value']
properties = [trigger['prop_id'] for trigger in dash.callback_context.triggered]
new_chart = {}
# If event is not a tab change, return the updated chart
if 'tabs-select.value' not in properties: # FIXME: replace tabs-select with actual keyname (?)
if self.takes_args:
# Parse the arguments to generate a new plot
kwargs = {key: a_in[key]['value'] for key in self.input_ids[1:]}
new_chart = self.func_map[name_func](self.data, height=650, **kwargs)
else:
new_chart = self.func_map[name_func]()
# Example Mapping Output. Alternatively, just: `return [new_chart]`
return map_outputs(outputs, [(self.id_chart, 'figure', new_chart)])
return_layout⚓︎
def return_layout(
self
) -> dict
Return Dash application layout.
Returns:
| Type | Description |
|---|---|
| dict | Dash HTML object |
View Source
def return_layout(self) -> dict:
"""Return Dash application layout.
Returns:
dict: Dash HTML object
"""
self.verify_types_for_layout()
return html.Div(
[ # noqa: ECE001
html.Div(
[
dropdown_group(
'Plot Type:', self._il[self.id_func],
self.func_opts, value=self.func_opts[0]['label'],
),
dropdown_group(
'Template:', self._il[self.id_template],
self.t_opts, value=self.t_opts[0]['label'],
),
] + [
dropdown_group(
f'{dim}:', self._il[dim], self.col_opts,
value=self.default_dim_name.get(dim, None),
)
for dim in self.dims
] + [
dropdown_group(f'{dim}:', self._il[dim], [opts_dd(item, item) for item in items])
for dim, items in self.dims_dict.items()
], style={'width': '25%', 'float': 'left'},
),
min_graph(id=self._il[self.id_chart], style={'width': '75%', 'display': 'inline-block'}),
], style={'padding': '15px'},
)
run⚓︎
def run(
self,
**dash_kwargs: dict
) -> None
Launch the Dash server instance.
Parameters:
| Name | Description |
|---|---|
| **dash_kwargs | keyword arguments for Dash.run_server() |
View Source
def run(self, **dash_kwargs: dict) -> None:
"""Launch the Dash server instance.
Args:
**dash_kwargs: keyword arguments for `Dash.run_server()`
"""
self.app.run_server(**dash_kwargs) # pragma: no cover
verify_app_initialization⚓︎
def verify_app_initialization(
self
) -> None
Check that the app was properly initialized.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if child class has not called self.register_uniq_ids |
View Source
def verify_app_initialization(self) -> None:
"""Check that the app was properly initialized.
Raises:
RuntimeError: if child class has not called `self.register_uniq_ids`
"""
if not self._il.keys(): # pragma: no cover
raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')
verify_types_for_callbacks⚓︎
def verify_types_for_callbacks(
self
)
Verify data types of data members necessary for the callbacks of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_callbacks(self):
"""Verify data types of data members necessary for the callbacks of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.takes_args, bool):
errors.append(f'Expected self.takes_args="{self.takes_args}" to be bool')
if not (isinstance(self.data, pd.DataFrame) or self.data is None):
errors.append(f'Expected self.data="{self.data}" to be pd.DataFrame or None')
if not isinstance(self.func_map, OrderedDict):
errors.append(f'Expected self.func_map="{self.func_map}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
verify_types_for_layout⚓︎
def verify_types_for_layout(
self
)
Verify data types of data members necessary for the layout of this tab.
Raises:
| Type | Description |
|---|---|
| RuntimeError | if any relevant data members are of the wrong type |
View Source
def verify_types_for_layout(self):
"""Verify data types of data members necessary for the layout of this tab.
Raises:
RuntimeError: if any relevant data members are of the wrong type
"""
errors = []
if not isinstance(self.name, str):
errors.append(f'Expected self.name="{self.name}" to be str')
if not isinstance(self.dims, tuple):
errors.append(f'Expected self.dims="{self.dims}" to be tuple')
if not isinstance(self.dims_dict, OrderedDict):
errors.append(f'Expected self.dims_dict="{self.dims_dict}" to be OrderedDict')
if errors:
formatted_errors = '\n' + '\n'.join(errors)
raise RuntimeError(f'Found errors in data members:{formatted_errors}')
Created: August 5, 2022